package com.zenghm.recyclerview.expandable;

import android.util.SparseBooleanArray;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

/**
 * 可展开/收起二级列表适配器
 *
 * @author zenghm
 */
public abstract class BaseExpandableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

    private final SparseBooleanArray expandMap = new SparseBooleanArray();

    public abstract int getGroupCount();

    public abstract int getChildrenCount(int groupPosition);

    public abstract int getGroupViewType(int groupPosition);

    public abstract int getChildViewType(int groupPosition, int childPosition);

    @NonNull
    @Override
    public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);

    public abstract void onBindGroupViewHolder(@NonNull VH holder, int groupPosition);

    public abstract void onBindChildViewHolder(@NonNull VH holder, int groupPosition, int childPosition);

    /**
     * 是否展开
     *
     * @return true为展开状态，false为收起状态
     */
    public final boolean isExpanded(int groupPosition) {
        return expandMap.get(groupPosition, true);
    }

    /**
     * 展开子列表
     */
    public final void expand(int groupPosition) {
        expandMap.put(groupPosition, true);
        notifyDataSetChanged();
    }

    /**
     * 只展开当前子列表，其余收起
     */
    public final void expandOnly(int groupPosition) {
        int size = getGroupCount();
        for (int i = 0; i < size; i++) {
            expandMap.put(i, i == groupPosition);
        }
        notifyDataSetChanged();
    }

    /**
     * 展开所有子列表
     */
    public final void expandAll() {
        int size = getGroupCount();
        for (int i = 0; i < size; i++) {
            expandMap.put(i, true);
        }
        notifyDataSetChanged();
    }

    /**
     * 收起子列表
     */
    public final void collapse(int groupPosition) {
        expandMap.put(groupPosition, false);
        notifyDataSetChanged();
    }

    /**
     * 收起所有子列表
     */
    public final void collapseAll() {
        int size = getGroupCount();
        for (int i = 0; i < size; i++) {
            expandMap.put(i, false);
        }
        notifyDataSetChanged();
    }

    /**
     * 切换子列表的展开和收起
     */
    public final void toggle(int groupPosition) {
        if (isExpanded(groupPosition)) {
            collapse(groupPosition);
        } else {
            expand(groupPosition);
        }
    }

    @Override
    public final int getItemViewType(int position) {
        int[] temp = fromPosition(position);
        int groupPos = temp[0];
        int childPos = temp[1];
        if (childPos < 0) {
            return getGroupViewType(groupPos);
        } else {
            return getChildViewType(groupPos, childPos);
        }
    }

    @Override
    public final void onBindViewHolder(@NonNull VH holder, int position) {
        int[] temp = fromPosition(position);
        int groupPos = temp[0];
        int childPos = temp[1];
        if (childPos < 0) {
            onBindGroupViewHolder(holder, groupPos);
        } else {
            onBindChildViewHolder(holder, groupPos, childPos);
        }
    }

    @Override
    public final int getItemCount() {
        int itemCount, groupCount;
        itemCount = groupCount = getGroupCount();
        for (int groupPos = 0; groupPos < groupCount; groupPos++) {
            if (isExpanded(groupPos)) {
                itemCount += getChildrenCount(groupPos);
            }
        }
        return itemCount;
    }

    private int[] fromPosition(int position) {
        if (position >= 0) {
            int groupPos = 0;
            int childPos = position;
            int groupCount = getGroupCount();
            for (; groupPos < groupCount; groupPos++) {
                if (childPos == 0) {
                    return new int[]{groupPos, -1};
                }
                childPos--;
                if (isExpanded(groupPos)) {
                    int childCount = getChildrenCount(groupPos);
                    if (childPos < childCount) {
                        return new int[]{groupPos, childPos};
                    } else {
                        childPos -= childCount;
                    }
                }
            }
        }
        return new int[]{-1, -1};
    }
}
